from .Vector import Vecotr   ##  在当前这个包的Vector文件中 引入vector类


class Matrix :

    def __init__(self , list2d):  ## 二维数组 表示矩阵
        self._values = [row[:] for row in list2d]  ## 取出 list2d 中的每一行 ， 把每行的内容都复制一遍 ， 形成一个新的列表 ， 这些列表又组成 一个新列表（二维数组） [:]“全选”的切片操作

    @classmethod   ## 类方法 ， 调用这个发放需要重建矩阵实例 ，直接在矩阵类上调用
    def zero(cls , r, c):
        """返回一个r行c列的零矩阵
        @classmethod 的核心作用 它允许你在不创建类的实例的情况下，调用这个方法，并且这个方法可以访问和操作类本身。
          @staticmethod"""
        return cls([[0] * c for _ in range(r)])

    @classmethod
    def identity(cls , n):
        """"返回一个n行n列的单位矩阵"""
        m = [[0] * n for _ in range(n)]   ## 二位列表 n行 每一行都有n个 0
        for i  in range(n) : # 从 0 - n
            m[i][i] = 1;     # 第i行i列改为1 ， 其他保持0
        return  cls(m)   # 返回matrix对象

    def T(self):
        """返回矩阵的转置矩阵
        将原矩阵的行转为列，列转为行
        """
        # 使用列表推导式创建转置矩阵
        # 对于每一列j，取出所有行在该列的元素组成新的行
        return Matrix([[self._values[i][j] for i in range(self.row_num())]
                      for j in range(self.col_num())])

    def shape(self):
        """返回矩阵的形状 ： （行数 ， 列数）
        由于包含 （行数 ， 列数） 两个信息 所以通常是返回 二元组 形式
        行 ： len(self._values)  列表的长度
        列 ： len(self._values[0]) 第一个行向量 ， 里面有几个元素 相应就是有几列  （对于这个矩阵来说，每一行个数都一样 ， 并且矩阵至少要有一行） """
        return len(self._values) , len(self._values[0])

    def dot (self , another):
        """返回矩阵乘法结果"""
        if isinstance(another , Vecotr): # 传入是否是向量
            ## 矩阵和向量的乘法  矩阵列数是否等于向量的元素数量？
            assert self.col_num() == len(another) ,\
                "Error in Matrix-Vector Multiplication."
            ## 矩阵 * 向量 得到的还是向量
            return Vecotr([self.row_vector(i).dot(another) for i in range(self.row_num())])
        if isinstance(another , Matrix) : # 传入是否是矩阵
            ## 矩阵和矩阵的乘法    前矩阵列数 必须等于 后矩阵行数
            assert  self.col_num() == another.row_num() ,\
                "Error in Matrix-Matrix Multiplication . "
            return Matrix([[self.row_vector(i).dot(another.col_vector(j))
                            for j in range(another.col_num())]
                           for i in range(self.row_num())])
        """每一次从前面的矩阵拿出一行 对于这一行向量 - 每次从后面的矩阵拿出一列
        前面的第i行和后面的第j列 进行点乘  点乘的结果就算结果矩阵的第 ij个元素 - i行j列"""

    def row_num(self):
        """返回矩阵的行数
        shape 元组的第1个 元素 就是 矩阵 行数"""
        return self.shape()[0]

    def col_num(self):
        """返回矩阵列数
        shape 元组的第2个 元素 就是 矩阵 列数"""
        return self.shape()[1]

    def size(self):
        """返回矩阵的元素个数"""
        r ,c = self.shape()
        return r*c

    def row_vector(self , index):
        """返回矩阵的第index个行向量"""
        return  Vecotr(self._values[index])
    def col_vector(self , index):
        """返回矩阵的第index个列向量
        取出矩阵对应每一行 把每一行的第index个元素拿出来 ， 构成一个向量"""
        return Vecotr([row[index] for row in self._values])


    ## 打印的时候显示
    def __repr__(self):
        return "Matrix({}).".format(self._values)
    __str__ = __repr__  ## 让他们相等 不区分方法返回字符串

    __len__ = row_num ## 等同于 二维列表多少行

    def __getitem__(self, pos):
        """返回矩阵pos位置的元素  ，  利用元组 传递行、列"""
        r , c = pos  ##  元组解包（Tuple Unpacking）
        return self._values[r][c]
    def __add__(self, another):
        """返回两个矩阵的加法结果
        先判断两个矩阵形状一样"""
        assert  self.shape() == another.shape(),\
            "Error in adding . Shape of matrix must be same ."
        """python特有的列表表达式 - 更加 pythonic ！
        新建一个新的matrix类 传入一个新的 加和 二维数组"""
        return Matrix([[a + b for a,b in zip(self.row_vector(i) , another.row_vector(i))]
                       for i in range(self.row_num())])
    def __sub__(self, another):
        """返回两个矩阵的减法结果
        先判断两个矩阵形状一样"""
        assert  self.shape() == another.shape(),\
            "Error in subtracting . Shape of matrix must be same ."
        """python特有的列表表达式 - 更加 pythonic ！
        新建一个新的matrix类 传入一个新的 加和 二维数组"""
        return Matrix([[a - b for a,b in zip(self.row_vector(i) , another.row_vector(i))]
                       for i in range(self.row_num())])
    def __mul__(self, k):
        """返回矩阵的数量乘结果 ： self * k
        创建新的矩阵 - 传入二维列表"""
        return Matrix([[e * k for  e in self.row_vector(i)]
                       for i  in range(self.row_num())])
    def __rmul__(self, k):
        """返回矩阵的数量乘结果 - 右乘 ： k * self
        一个数字乘一个矩阵是拥有交换律的 ： 可以使用 mul 结果一致"""
        return self * k
    def __truediv__(self, k):
        """"返回数量除法的结果 ： self / k
        可以转成数量的乘法 ， 也就是用 1/k 乘 当前矩阵"""
        return (1 / k) * self
    def __pos__(self):
        """返回矩阵取正的结果"""
        return 1 * self
    def __neg__(self):
        """返回矩阵取负的结果"""
        return -1 * self  ## 矩阵的数量乘法来表示



